// SCardFuzz.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "appinitdll.h"

//
// Heap helpers
//

LPVOID Alloc(DWORD cb)
{
    return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
}

void Free(LPVOID pv)
{
    HeapFree(GetProcessHeap(), 0, pv);
}

//
// Flow macros
//

static 
void
WINAPI
_OutputDbgStr(
    __in  LPSTR szMsg,
    __in  DWORD dwStatus)
{
    CHAR rgsz [256];

    StringCbPrintfA(
        rgsz,
        sizeof(rgsz),
        "ERROR: %s - 0x%x\n",
        szMsg,
        dwStatus);
    OutputDebugStringA(rgsz);
}

#define TRY_DWORD(_X) {                                             \
    if (ERROR_SUCCESS != (status = _X)) {                           \
        _OutputDbgStr(#_X, status);                                 \
        __leave;                                                    \
    }                                                               \
}

#define TRY_BOOL(_X) {                                              \
    if (FALSE == (_X)) {                                            \
        status = GetLastError();                                    \
        _OutputDbgStr(#_X, status);                                 \
        __leave;                                                    \
    }                                                               \
}

#define TRY_ALLOC(_X) {                                             \
    if (NULL == (_X)) {                                             \
        status = ERROR_NOT_ENOUGH_MEMORY;                           \
        __leave;                                                    \
    }                                                               \
}

//
// Display usage information to console
// 
void
WINAPI
Usage(void)
{
    wprintf(L"SCardFuzz Version 1.0 Copyright 2007 JW Secure, Inc.\n");
    wprintf(L"\nUsage:\n");
    wprintf(L" scardfuzz.exe\n");
}

//
// Print out hex data to console
//
#define CROW                                                16
static void PrintBytes(LPSTR szTitle, PBYTE pbData, DWORD cbData)
{
    //DWORD iByte = 0, iRowItem = 0;
    CHAR rgbRow [256];
    DWORD cbRow = sizeof(rgbRow);

    StringCbPrintfA(
        rgbRow, sizeof(rgbRow), "\n%s -- %d bytes\n", szTitle, cbData);
    OutputDebugStringA(rgbRow);

    CryptBinaryToStringA(
        pbData,
        cbData,
        CRYPT_STRING_HEXASCIIADDR,
        rgbRow,
        &cbRow);
    OutputDebugStringA(rgbRow);

        /*
    StringCbPrintfA(
        rgbRow, sizeof(rgbRow), "\n%s -- %d bytes\n", szTitle, cbData);
    OutputDebugStringA(rgbRow);

    while (iByte < cbData)
    {
        for (   iRowItem = 0; 
                iRowItem < CROW && iByte < cbData; 
                iRowItem++, iByte++)
            StringCbPrintfA(
                rgbRow + (iRowItem * 3), 
                sizeof(rgbRow) - (iRowItem * 3),
                "%02X ", 
                pbData[iByte]);

        OutputDebugStringA(rgbRow);
        OutputDebugStringA("\n");
    }
*/
}

BYTE rgbAXALTO_READ_FILE []                 = { 0x00, 0xc0, 0x00, 0x00 };
DWORD dwAXALTO_READ_FILE_SIZE_INDEX         = 4;

//
// Test replacement routine
//
LONG 
WINAPI
_MySCardTransmit(
    IN SCARDHANDLE hCard,
    IN LPCSCARD_IO_REQUEST pioSendPci,
    IN LPCBYTE pbSendBuffer,
    IN DWORD cbSendLength,
    IN OUT LPSCARD_IO_REQUEST pioRecvPci,
    OUT LPBYTE pbRecvBuffer,
    IN OUT LPDWORD pcbRecvLength)
{
    DWORD cbBogus = 0;
    DWORD iBogusByte = 0;

    //
    // Complete the requested data exchange w/ the card
    // 

    LONG lReturn = SCardTransmit(
        hCard, 
        pioSendPci,
        pbSendBuffer,
        cbSendLength,
        pioRecvPci,
        pbRecvBuffer,
        pcbRecvLength);
    PrintBytes("SCardTransmit : Sent", (PBYTE) pbSendBuffer, cbSendLength);
    PrintBytes(
        "SCardTransmit : Received (Actual)", pbRecvBuffer, *pcbRecvLength);

    //
    // Modify the received data for testing up the stack
    // 

    if (2 < *pcbRecvLength)
    {
        cbBogus = (rand() % *pcbRecvLength) + 1;
        for ( ; iBogusByte < cbBogus; iBogusByte++)
            pbRecvBuffer [iBogusByte] = (BYTE) rand();
        PrintBytes(
            "SCardTransmit : Received (Fuzzed)", pbRecvBuffer, *pcbRecvLength);
    }

    /*
    //
    // Check if this is a read-file command
    // 

    if (cbSendLength >= 1 + sizeof(rgbAXALTO_READ_FILE) &&
        0 == memcmp(
            rgbAXALTO_READ_FILE, pbSendBuffer, sizeof(rgbAXALTO_READ_FILE)))
    {
        // 
        // Set the returned file data size byte to a random value
        //

        pbRecvBuffer [dwAXALTO_READ_FILE_SIZE_INDEX] = (BYTE) rand();
    }
    */

    return lReturn;
}

//
// Test entry point
//
int _tmain(int argc, _TCHAR* argv[])
{
    DWORD status = ERROR_SUCCESS;
    BOOL fInvalidParam = FALSE;
    LPWSTR wszError = NULL;
    HCRYPTPROV hProv = 0;
    HMODULE hMod = NULL;

    __try
    {
        if (NULL == (hMod = LoadLibraryA("axaltocm.dll")))
        {
            status = GetLastError();
            __leave;
        }

        /*
        //
        // Verify that a smart card key container exists
        // 

        if (FALSE == CryptAcquireContext(
            &hProv, NULL, MS_SCARD_PROV, PROV_RSA_FULL, CRYPT_SILENT))
        {
            TRY_BOOL(CryptAcquireContext(
                &hProv, NULL, MS_SCARD_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET));
        }
        */

        //
        // Hook the binary
        // 

        TRY_DWORD(PatchImage(
            "axaltocm.dll",
            FALSE,
            "winscard.dll",
            "SCardTransmit",
            (PROC) _MySCardTransmit));

        //
        // Run the test
        // 

        srand((unsigned) time(NULL));

        while (TRUE)
        {
            if (TRUE == CryptAcquireContext(
                &hProv, NULL, MS_SCARD_PROV, PROV_RSA_FULL, CRYPT_SILENT))
            {
                CryptReleaseContext(hProv, 0);
                hProv = 0;
            }
        }
    }
    __finally
    {
        if (NULL != hMod)
            FreeLibrary(hMod);
        if (0 != hProv)
            CryptReleaseContext(hProv, 0);
    }

    if (TRUE == fInvalidParam)
    {
        Usage();
    }
    else if (ERROR_SUCCESS != status)
    {
        if (0 != FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
            NULL,
            status,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            (LPWSTR) &wszError,
            0,
            NULL))
        {
            wprintf(L" failed\n0x%x - %s", status, wszError);
            if (NULL != wszError)
                LocalFree(wszError);
        }
        else
        {
            wprintf(L" failed\n0x%x\n", status);
        }
    }
    else
    {
        printf("Success\n");
    }

    return status;
}

